package uk.co.richardwkirk.parkrun.geo;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import uk.co.richardwkirk.parkrun.data.events.Event;
import uk.co.richardwkirk.parkrun.data.events.EventSortComparator;
import uk.co.richardwkirk.parkrun.news.NewsSubject;
import uk.co.richardwkirk.parkrun.web.ParkrunURLGenerator;
import uk.co.richardwkirk.parkrun.web.ParkrunURLGenerator.ParkrunWebPages;


public class Region implements NewsSubject {

	HashMap<Integer, Region> subRegions = new HashMap<Integer, Region>();
	
	int id = 0;
	String name = null;
	Location location = null;
	String url = null;
	int zoom = 0;
	Region parentRegion = null;
	int errorCount = 0;

	public Region() {
		super();
	}
	
	public Region getParentRegion() {
		return this.parentRegion;
	}
	
	public void setParentRegion(Region parentRegion) {
		this.parentRegion = parentRegion;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Location getLocation() {
		return location;
	}

	public void setLocation(Location location) {
		this.location = location;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public int getZoom() {
		return zoom;
	}

	public void setZoom(int zoom) {
		this.zoom = zoom;
	}

	public int countRegions() {
		int count = 0;
		count += subRegions.size();
		for (Region subRegion : subRegions.values()) {
			count += subRegion.countRegions();
		}
		return count;
	}

	public Region getRegion(int i) {
		if (subRegions.containsKey(i)) {
			return subRegions.get(i);
		}
		else {
			return findSubRegion(i);
		}
	}
	
	public Region getRegion(String searchName) {
		if (name.equals(searchName)) {
			return this;
		}
		else {
			return findSubRegion(searchName);
		}
	}

	private Region findSubRegion(String searchName) {
		// Look for the region we want in each sub region
		for (Region subRegion : subRegions.values()) {
			Region foundRegion = subRegion.getRegion(searchName);
			if (foundRegion != null) {
				return foundRegion;
			}
		}
		// Region not found
		return null;
	}
	
	private Region findSubRegion(int i) {
		// Look for the region we want in each sub region
		for (Region subRegion : subRegions.values()) {
			Region foundRegion = subRegion.getRegion(i);
			if (foundRegion != null) {
				return foundRegion;
			}
		}
		// Region not found
		return null;
	}

	public Event getEvent(String eventName, boolean useFullName) {
		// Look for the event we want in each sub region
		for (Region subRegion : subRegions.values()) {
			Event foundEvent = subRegion.getEvent(eventName, useFullName);
			if (foundEvent != null) {
				return foundEvent;
			}
		}
		// Region not found
		return null;
	}
	
	public Event getEvent(String eventName) {
		return getEvent(eventName, false);
	}
	
	public Event getEventByFullName(String eventName) {
		return getEvent(eventName, true);
	}

	public int countEvents() {
		int eventCount = 0;
		for (Region subRegion : subRegions.values()) {
			eventCount += subRegion.countEvents();
		}
		return eventCount;
	}

	public void addRegion(Region region) throws GeoDataException {
		subRegions.put(region.getId(), region);
		region.setParentRegion(this);
	}

	public void addEvent(Event event) throws GeoDataException {
		throw new GeoDataException("Non-leaf regions cannot have events.");
	}

	public Collection<Event> getAllEvents() {
		LinkedList<Event> allEvents = new LinkedList<Event>();
		for (Region subRegion : subRegions.values()) {
			allEvents.addAll(subRegion.getAllEvents());
		}
		return allEvents;
	}

	public Collection<Region> getSubRegions() {
		return subRegions.values();
	}
	
	public Collection<Region> getSortedSubRegions() {
		List<Region> list = new ArrayList<Region>();
		list.addAll(subRegions.values());
		Collections.sort(list, new RegionSortComparator());
		return list;
	}
	
	public Collection<Event> getSortedEvents() {
		List<Event> list = new ArrayList<Event>();
		list.addAll(getAllEvents());
		Collections.sort(list, new EventSortComparator());
		return list;
	}

	public String getParkrunSiteURL() {
		// Do we have a url at this level?
		if (url != null && !url.trim().equals("")) {
			return url;
		}
		// If we have a parent, get the URL from them
		else if (parentRegion != null) {
			return parentRegion.getParkrunSiteURL();
		}
		// Nuts. No URL. Better use the default.
		else {
			return ParkrunURLGenerator.PARKRUN_DEFAULT_UK_SITE_URL;
		}
	}
	
	public String getRegionURL(ParkrunWebPages pageType) {
		String siteURL = getParkrunSiteURL();
		ParkrunURLGenerator urlGenerator = new ParkrunURLGenerator(siteURL);
		return urlGenerator.createRegionalURL(pageType);
	}

	
	public void setErrorCount(int errorCount) {
		this.errorCount = errorCount;
	}
	
	public int getErrorCount() {
		return errorCount;
	}

	
	/**
	 * NEWS FUNCTIONS FOLLOW
	 */
	
	
	@Override
	public String getSubjectName() {
		return getName();
	}

	@Override
	public String getNewsFeedUrl() {
		return getRegionURL(ParkrunWebPages.NewsFeed);
	}


}